<!--
 * @Author: qinruiguang
 * @LastEditors: qinruiguang
 * @Date: 2021-08-27 17:00:24
 * @LastEditTime: 2021-08-27 17:35:09
-->
<template>
  <div class="main" ondragstart="return false;">
    <div class="bg"></div>
    <div class="but out" @click="out" title="关闭">
      <img src="@/assets/html/out.png" alt="" />
    </div>
    <div class="title" v-if="localStream">
      <span><i class="el-icon-s-home" />{{ gid }}</span>
      <span><i class="el-icon-s-custom" />{{ name }}</span>
    </div>
    <transition name="el-zoom-in-bottom" v-if="!localStream">
      <div v-show="showUser" class="user transition-box">
        <el-input class="gid" placeholder="请输入房间号" v-model="gid" @input="
          () => {
            this.gid = this.gid.replace(/[^\d]/g, '');
          }
        ">
          <template slot="prepend">房间号&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</template>
        </el-input>
        <el-input class="name" placeholder="请输入姓名/手机号" v-model="name">
          <template slot="prepend">姓名/手机号</template>
        </el-input>
        <!-- <div class="btn">
          <el-radio-group v-model="radio" @change="onchange">
            <el-radio v-for="item in vdl" :label="item.id" :key="item.id" class="name">{{ item.name }}
            </el-radio>
          </el-radio-group>
        </div> -->
        <el-select :popper-append-to-body="false" style="width: 100%; margin-top: 10px; -webkit-app-region: none"
          v-model="radio" placeholder="请选择投影">
          <el-option v-for="item in vdl" :key="item.id" :label="item.name" :value="item.id">
          </el-option>
        </el-select>
        <el-select :popper-append-to-body="false" v-if="radio == '00000'"
          style="width: 100%; margin-top: 10px; -webkit-app-region: none" v-model="cameraVal" placeholder="请选择USB摄像头">
          <el-option v-for="item in devicesList" :key="item.value" :label="item.label" :value="item.value">
          </el-option>
        </el-select>
        <el-button type="primary" class="btn" round @click="btnclick">连接会议</el-button>
      </div>
    </transition>
    <div class="videos" id="videos" style="-webkit-app-region: none" v-show="localStream">
      <div class="line">
        <video ref="localAudio" autoplay playsinline muted width="320" height="240" @click.stop="maxVideoFun('-1')"
          :class="{ maxs: maxVideo === '-1' }"></video>
      </div>
      <div class="line" v-for="(item, i) in videoLine" :key="item.key">
        {{ funVideo(item) }}
        <video :class="{ ['video_' + item.key]: true, maxs: maxVideo === i }" autoplay playsinline muted width="320"
          height="240" @click.stop="maxVideoFun(i)"></video>
        <div class="btn">
          <i class="el-icon-microphone" v-if="!item.muted" @click="videoClick(item)" />
          <i class="el-icon-turn-off-microphone" v-if="item.muted" @click="videoClick(item)" />
        </div>
      </div>
    </div>
  </div>
</template>
<script>
export default {
  data() {
    return {
      Socket: null,
      gid: "", //房间id
      name: "", //用户名称
      showUser: false,
      wsUrl: "",
      localStream: null,
      radio: "",
      pc: [], //连接视频对象集合,
      user: [], //用户集合
      vdl: [], //摄像头列表 铺抓对象列表
      cameraVal: "", //选中摄像仪
      devicesList: [], //摄像头列表
      maxVideo: "",//放大视频
      videoLine: [],
      configuration: {
        iceServers: [
          {
            urls: "stun:150.158.82.144:5001",
            username: "demo",
            credential: "demo",
          },
          {
            urls: "turn:150.158.82.144:5001",
            username: "demo",
            credential: "demo",
          },
        ],
      },
    };
  },
  created() {
  },
  async mounted() {
    this.ipc.send("message", {
      type: "window-show",
      id: this.urlParam("id"),
    });
    setTimeout(() => {
      this.showUser = true;
    }, 250);
    let ret = await this.ipc.invoke("rtc");
    window.addEventListener("wsOnmessage", this.onmessage);
    if (ret) {
      this.vdl = ret;
      this.vdl.push({
        id: "00000",
        name: "摄像头",
      });
    }
    let devices = await navigator.mediaDevices.enumerateDevices();
    devices.map((rd) => {
      if (rd.kind == "videoinput") {
        let obj = {
          label: rd.label,
          value: rd.deviceId,
        };
        this.devicesList.push(obj);
      }
    });
    // debugger;
    // getbase64().then((res) => {
    //   document.querySelector("html").style = "opacity: 1;";
    //   let img = document.createElement("img");
    //   img.src = res;
    //   document.querySelector("#app").appendChild(img);
    // });
  },
  methods: {
    maxVideoFun(c) {
      if (this.maxVideo === c) {
        this.maxVideo = ""
      } else {
        this.maxVideo = c
      }
    },
    videoClick(div) {
      div.muted = !div.muted;
      document.querySelector(".video_" + div.key).muted = div.muted;
    },
    funVideo(d) {
      setTimeout(() => {
        document.querySelector(".video_" + d.key).srcObject = d.stream;
      }, 1);
    },
    link(id) {
      //开始搭建连接
      this.StartCall(id, true);
    },
    StartCall(parterName, createOffer) {
      this.pc[parterName] = new RTCPeerConnection(this.configuration);

      //如果已经有本地流，那么直接获取Tracks并调用addTrack添加到RTC对象中。
      if (this.localStream) {
        this.localStream.getTracks().forEach((track) => {
          this.pc[parterName].addTrack(track, this.localStream); //should trigger negotiationneeded event
        });
      } else {
        //否则需要重新启动摄像头并获取
      }
      //如果是呼叫方,那么需要createOffer请求
      if (createOffer) {
        //每当WebRTC基础结构需要你重新启动会话协商过程时，都会调用此函数。它的工作是创建和发送一个请求，给被叫方，要求它与我们联系。
        this.pc[parterName].onnegotiationneeded = () => {
          //https://developer.mozilla.org/zh-CN/docs/Web/API/RTCPeerConnection/createOffer

          this.pc[parterName]
            .createOffer()
            .then((offer) => {
              return this.pc[parterName].setLocalDescription(offer);
            })
            .then(() => {
              //把发起者的描述信息通过Signal Server发送到接收者
              let obj = {
                openID: "videoYc",
                type: "offer",
                offer: JSON.stringify(this.pc[parterName].localDescription),
                to: parterName,
                name: this.name,
                gid: this.gid,
              };
              this.sendWS(obj);
            });
        };
      }
      this.pc[parterName].onaddstream = (e) => {
        this.videoLine.push({
          stream: e.stream,
          muted: false,
          key: parterName,
        });
        // console.log("有流输出了");
        // // this.$refs.remoteAudio.srcObject = e.stream;
        // if (document.getElementById(`${parterName}-video`)) {
        //   document.getElementById(`${parterName}-video`).srcObject = e.stream;
        // } else {
        //   let id = `video-${parterName}`;
        //   let newVideo = document.createElement("video");
        //   let line = document.createElement("div");
        //   line.className = id
        //   line.style = `width: 320px;height: 240px;z-index: 8;margin-right:16px;object-fit:fill;display: inline-block;`
        //   newVideo.id = id;
        //   newVideo.style = `width: 320px;height: 240px;z-index: 1;object-fit:fill;`
        //   newVideo.srcObject = e.stream;
        //   newVideo.setAttribute("controls", true);
        //   newVideo.setAttribute("autoplay", true);
        //   newVideo.setAttribute("playsinline", true);
        //   line.appendChild(newVideo)
        //   document.getElementById("videos").appendChild(line);
        //   line
        //   newVideo.onloadedmetadata = function () {
        //     // ctx.drawImage(video,0, 0)
        //     this.muted = true;//静音

        //   };

        // }
      };
      this.pc[parterName].onicecandidate = (evt) => {
        let json = JSON.stringify(evt.candidate);
        if (evt.candidate && json.indexOf("150.158.82.144") >= 0) {
          let obj = {
            type: "candidate",
            gid: this.gid,
            candidate: json,
            name: this.name,
            to: parterName,
          };
          this.sendWS(obj);
        }
      };
      //当向连接中添加磁道时，track 事件的此处理程序由本地WebRTC层调用。例如，可以将传入媒体连接到元素以显示它。详见 Receiving new streams 。
      // this.pc[parterName].ontrack = (ev) => {
      //   let str = ev.streams[0];

      //   if (document.getElementById(`${parterName}-video`)) {
      //     document.getElementById(`${parterName}-video`).srcObject = str;
      //   } else {
      //     let newVideo = document.createElement('video');
      //     newVideo.id = `${parterName}-video`;
      //     newVideo.autoplay = true;
      //     newVideo.controls = true;
      //     //newVideo.className = 'remote-video';
      //     newVideo.srcObject = str;

      //     document.getElementById('videos').appendChild(newVideo);
      //   }
      // }
    },
    sendWS(message) {
      if (this.Socket !== null && this.Socket.readyState === 3) {
        this.Socket.close();
        this.createSocket();
      } else if (this.Socket.readyState === 1) {
        this.Socket.send(JSON.stringify(message));
      } else if (this.Socket.readyState === 0) {
      }
    },
    createSocket(e) {
      this.Socket && this.Socket.close();
      if (!this.Socket) {
        console.log("建立websocket连接");
        this.Socket = new WebSocket(this.wsUrl);
        this.Socket.onopen = () => {
          console.log("完成连接");
          //告诉房间里所有的用户
          let obj = {
            type: "logins",
            name: this.name,
            gid: this.gid,
          };
          this.sendWS(obj);
          this.pc.push(this.name);
        };
        this.Socket.onmessage = (e) => {
          this.onmessage(JSON.parse(e.data || `{}`));
        };
        this.Socket.onerror = () => {
          console.log("连接失败重连中");
          this.Socket.close();
          if (this.Socket.readyState !== 3) {
            this.Socket = null;
            this.createSocket();
          }
        };
        this.Socket.onclose = () => {
          if (this.Socket.readyState !== 2) {
            this.Socket = null;
            this.createSocket();
          }
        };
      } else {
        console.log("websocket已连接");
      }
    },
    async videoShow(myStream) {
      this.localStream = myStream;
      //展示本地媒体流
      this.$refs.localAudio.srcObject = myStream;
      //服务配置
      // if (!sdk.isDev) {
      //   this.wsUrl =
      //     `ws://127.0.0.1:3000/lg?name=` + this.name + "&group=" + this.gid;
      // } else {
      this.wsUrl =
        `wss://w3cjs.cn/lg?name=` + this.name + "&group=" + this.gid;
      // }

      await this.createSocket();
    },
    onmessage(e) {
      const msg = e;
      if (msg == "欢迎使用！") return;
      let data = JSON.parse(msg);
      switch (data.type) {
        case "logins":
          //链接开始
          console.log(data);
          if (data.name == this.name) {
            return;
          }
          //收到房间发送过来的身份
          this.user.push(data.name);
          this.link(data.name);
          break;
        case "offer":
          if (!data.offer) return;
          console.log("offer", data);
          this.handleOffer(JSON.parse(data.offer), data.name);
          break;
        case "answer":
          if (!data.answer) return;
          console.log("answer", data);
          this.handleAnswer(JSON.parse(data.answer), data.name);
          break;
        //when a remote peer sends an ice candidate to us
        case "candidate":
          if (data.candidate.indexOf("null") >= 0) return;
          console.log("candidate", data);
          this.handleCandidate(JSON.parse(data.candidate), data.name);
          break;
        case "userOut":
          //删除协议里的媒体
          delete this.pc[data.name];
          //删除视频流
          let dom = document.querySelector("#" + "video-" + data.name);
          let ctxs = document.querySelector("." + "video-" + data.name);
          dom ? dom.remove() : "";
          ctxs ? ctxs.remove() : "";
          this.user.indexOf(data.name) >= 0
            ? this.user.splice(this.user.indexOf(data.name), 1)
            : "";
          //删除用户集
          console.log(this.pc);
          break;
        default:
          break;
      }
    },
    handleCandidate(candidate, name) {
      //如果ice candidate非空（当candidate为空时，那么本次协商流程到此结束了）
      if (candidate) {
        var candidates = new RTCIceCandidate(candidate);
        //讲对方发来的协商信息保存
        this.pc[name].addIceCandidate(candidates).catch(); //catch err function empty
      }
    },
    handleAnswer(answer, name) {
      let desc = new RTCSessionDescription(answer);
      console.log("handleAnswer");
      this.pc[name].setRemoteDescription(desc);
    },
    async handleOffer(offer, name) {
      this.StartCall(name, false);
      //把发送者(offer)的描述，存储在接收者的remoteDesc中。
      console.log("handleOffer");
      //按1-13流程走的
      this.pc[name].setRemoteDescription(new RTCSessionDescription(offer));
      this.pc[name].createAnswer(
        (answer) => {
          this.pc[name].setLocalDescription(answer);
          let obj = {
            type: "answer",
            answer: JSON.stringify(answer),
            to: name,
            name: this.name,
            gid: this.gid,
          };
          this.sendWS(obj);
        },
        (error) => {
          alert("创建answer错误");
        }
      );
    },
    wsStart() {
      navigator.getUserMedia =
        navigator.getUserMedia ||
        navigator.webkitGetUserMedia ||
        navigator.mozGetUserMedia ||
        navigator.msGetUserMedia;
      if (this.radio == "00000") {
        //摄像头
        navigator.mediaDevices
          .getUserMedia({
            audio: true,
            video: {
              mandatory: {
                sourceId: this.cameraVal,
              },
            },
          })
          .then((myStream) => {
            this.videoShow(myStream);
          })
          .catch((e) => { });
      } else {
        //桌面程序
        let os = sdk.os
        console.log(os.platform());
        let obj = {
          audio: {
            mandatory: {
              chromeMediaSource: "desktop",
              chromeMediaSourceId: this.radio,
            },
          },
          video: {
            mandatory: {
              chromeMediaSource: "desktop",
              chromeMediaSourceId: this.radio,
            },
          },
        }
        if (os.platform() != "win32") {
          delete obj.audio
          // delete obj.video.mandatory.chromeMediaSourceIds
        }
        console.log(obj);
        navigator.mediaDevices
          .getUserMedia(obj)
          .then((myStream) => {
            this.videoShow(myStream);
          })
          .catch((e) => {
            console.log("错误了", e);
          });
      }
    },
    btnclick() {
      if (this.gid == "") return this.err("请输入房间号！");
      if (this.name == "") return this.err("请输入姓名/手机号！");
      if (this.radio == "") return this.err("请选择共享列表！");
      this.post("/lg/name", {
        gid: this.gid,
        name: this.name,
      }).then(async (res) => {
        if (res.code === 200) {
          this.wsStart();
        } else {
          this.err("姓名/手机号被占用，请重新输入姓名/手机号！");
        }
      });
    },
    out() {
      this.ipc.send("message", {
        type: "window-close",
        id: this.urlParam("id"),
        showid: this.urlParam("id"),
      });
    },
  },
};
</script>

<style lang="less" scoped>
* {
  box-sizing: border-box;
}

.main {
  width: 100%;
  height: 100%;
  -webkit-app-region: drag;
  position: relative;

  >.bg {
    position: absolute;
    width: 100%;
    height: 100%;
    z-index: -1;
    background: url("@/assets/img/login.png");
    background-size: 100%;
    opacity: 0.6;
  }

  .title {
    height: 50px;
    padding: 0 16px;
    line-height: 50px;
    font-size: 16px;
    background: rgba(0, 0, 0, 0.05);

    >i {
      font-size: 20px;
      margin-right: 8px;
    }
  }

  .user {
    width: 320px;
    height: 240px;
    position: absolute;
    top: calc(50% - 120px);
    left: calc(50% - 160px);
    -webkit-app-region: none;

    >.name {
      margin-top: 16px;
    }

    >.btn {
      width: 100%;
      margin-top: 16px;
    }
  }

  >.but {
    position: absolute;
    width: 50px;
    height: 50px;
    // background: rgba(255, 255, 255, 0.1);
    -webkit-app-region: none;
    padding: 4px;

    >img {
      width: 24px;
      height: 24px;
      position: absolute;
      top: calc(50% - 12px);
      left: calc(50% - 12px);
    }

    &.out {
      top: 0;
      cursor: pointer;
      right: 0;

      &:hover {
        background: rgba(240, 23, 23, 0.856);
      }
    }
  }

  >.content {
    height: 100%;
    width: 100%;
    padding: 16px;
    padding-top: 30px;
    color: #333333;

    >.img {
      width: 100%;
      height: 80px;

      //   text-align: center;
      >.imgs {
        width: 80px;
        height: 80px;
        border-radius: 50%;
        border: 1px #eaeaea solid;
        -webkit-app-region: none;
        cursor: pointer;

        &:hover {
          border: 1px #0578fc solid;
        }
      }
    }

    >.line {
      width: 100%;
      min-height: 24px;
      line-height: 24px;
      margin-top: 10px;
      display: flex;
      flex-direction: row;

      >i {
        width: 24px;
        height: 100%;
        font-size: 24px;
        margin-right: 8px;
      }

      >.title {
        width: 55px;
      }

      >.vals {
        width: calc(100% - 55px);
        -webkit-app-region: none;
      }
    }
  }

  >.videos {
    padding: 16px;
    height: calc(100% - 50px);
    max-height: calc(100% - 50px);
    overflow: hidden;
    overflow-y: scroll;
    font-size: 0;

    >.line {
      width: 320px;
      height: 240px;
      display: inline-block;
      margin-right: 16px;
      position: relative;
      overflow: hidden;

      >.maxs {
        position: fixed;
        left: 0;
        top: 0;
        width: 100%;
        height: 100%;
      }

      >video {
        object-fit: fill;
        z-index: 1;
      }

      >.btn {
        height: 50px;
        line-height: 50px;
        padding: 0 16px;
        background-color: rgba(0, 0, 0, 0.55);
        position: absolute;
        left: 0;
        width: 100%;
        bottom: -50px;
        transition: all 0.3s linear;

        >i {
          height: 50px;
          width: 50px;
          line-height: 50px;
          text-align: center;
          font-size: 30px;
          color: #fff;
          cursor: pointer;

          &:hover {
            color: #0578fc;
          }
        }
      }

      &:hover {
        >.btn {
          bottom: 0px;
        }
      }
    }
  }
}
</style>